package org.example.lotterysystem.service.impl;

import org.apache.commons.codec.digest.DigestUtils;
import org.example.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import org.example.lotterysystem.common.utils.JWTUtil;
import org.example.lotterysystem.common.utils.RegexUtil;
import org.example.lotterysystem.controller.param.ShortMessageLoginParam;
import org.example.lotterysystem.controller.param.UserLoginParam;
import org.example.lotterysystem.controller.param.UserPasswordLoginParam;
import org.example.lotterysystem.controller.param.UserRegisterParam;
import org.example.lotterysystem.dao.dataobject.Encrypt;
import org.example.lotterysystem.dao.dataobject.UserDO;
import org.example.lotterysystem.dao.mapper.UserMapper;
import org.example.lotterysystem.service.UserService;
import org.example.lotterysystem.service.VerificationCodeService;
import org.example.lotterysystem.service.dto.UserDTO;
import org.example.lotterysystem.service.dto.UserLoginDTO;
import org.example.lotterysystem.service.dto.UserRegisterDTO;
import org.example.lotterysystem.service.enums.UserIdentityEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;


import org.springframework.stereotype.Service;


import org.example.lotterysystem.common.exception.ServiceException;
import org.springframework.util.StringUtils;

import javax.validation.constraints.NotBlank;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class UserServiceImpl implements UserService {


    private final static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private VerificationCodeService verificationCodeService;


    @Override
    public UserRegisterDTO register(UserRegisterParam param) {

        // 校验注册信息
        checkRegisterInfo(param);

        // 加密私密数据（构造dao层请求）
        UserDO userDD = new UserDO();
        userDD.setUserName(param.getName());
        userDD.setEmail(param.getMail());
        userDD.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        userDD.setIdentity(param.getIdentity());
        if (StringUtils.hasText(param.getPassword())) {
            userDD.setPassword(DigestUtils.sha256Hex(param.getPassword()));
        }

        // 保存数据
        userMapper.insert(userDD);

        // 构造返回
        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setUserId(userDD.getId());

        return userRegisterDTO;
    }

    @Override
    public UserLoginDTO login(UserLoginParam param) {
        UserLoginDTO userLoginDTO;

        // 类型检查 类型转换 java14版本及以上
        if (param instanceof UserPasswordLoginParam loginParam) {
            //密码登录流程
            userLoginDTO = loginByUserPassword(loginParam);

        } else if (param instanceof ShortMessageLoginParam loginParam) {
            //短信验证码登录流程
            userLoginDTO = loginByShortMessage(loginParam);

        } else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);
        }

        return userLoginDTO;
    }

    @Override
    public List<UserDTO> findUserInfo(UserIdentityEnum identity) {
        String identityString = null == identity ? null : identity.name();
        // 查表
        List<UserDO> userDOList = userMapper.selectUserListByIdentity(identityString);
        List<UserDTO> userDTOList = userDOList.stream()
                .map(userDO -> {
                    UserDTO userDTO = new UserDTO();
                    userDTO.setUserId(userDO.getId());
                    userDTO.setUserName(userDO.getUserName());
                    userDTO.setEmail(userDO.getEmail());
                    userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
                    userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
                    return userDTO;

                }).collect(Collectors.toList());
        return userDTOList;
    }

    /**
     * 验证码登录
     *
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByShortMessage(ShortMessageLoginParam loginParam) {
        if (!RegexUtil.checkMobile(loginParam.getLoginMobile())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_ERROR);
        }

        // 获取用户信息
        UserDO userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginMobile()));
        if (userDO == null) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity())
                && !loginParam.getMandatoryIdentity()
                .equalsIgnoreCase(userDO.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        // 校验验证码
        String code = verificationCodeService.getVerificationCode(loginParam.getLoginMobile());
        if (!loginParam.getVerificationCode().equals(code)) {
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }
        // 塞入返回值（JWT）
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", userDO.getId());
        claims.put("identity", userDO.getIdentity());
        String token = JWTUtil.genJwt(claims);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));

        return userLoginDTO;

    }

    /**
     * 密码登录
     *
     * @param loginParam
     * @return
     */

    private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {
        UserDO userDD = null;
        // 判断手机登录还是邮箱登录
        if (RegexUtil.checkMail(loginParam.getLoginName())) {
            // 邮箱登录
            // 根据邮箱查询用户表
            userDD = userMapper.selectByMail(loginParam.getLoginName());
        } else if (RegexUtil.checkMobile(loginParam.getLoginName())) {
            // 手机号登录
            // 根据手机号查询用户表
            userDD = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));

        } else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }

        //校验登录信息
        if (userDD == null) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity())
                && !loginParam.getMandatoryIdentity()
                .equalsIgnoreCase(userDD.getIdentity())) {
            // 强制身份登录，身份校验不登陆
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        } else if (!DigestUtils.sha256Hex(loginParam.getPassword())
                .equals(userDD.getPassword())) {
            //校验密码不通过
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        // 塞入返回值（JWT）
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", userDD.getId());
        claims.put("identity", userDD.getIdentity());
        String token = JWTUtil.genJwt(claims);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDD.getIdentity()));

        return userLoginDTO;
    }

    private void checkRegisterInfo(UserRegisterParam param) {


        if (param == null) {
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        // 校验邮箱格式 xxx@xxx.xxx
        if (!RegexUtil.checkMail(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }

        // 校验手机号格式
        if (!RegexUtil.checkMobile(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_ERROR);
        }
        // 校验身份信息
        if (UserIdentityEnum.forName(param.getIdentity()) == null) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        // 校验管理员密码必填
        if (param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())
                && !StringUtils.hasText(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);

        }

        // 密码校验，至少6位
        if (StringUtils.hasText(param.getPassword())
                && !RegexUtil.checkPassword(param.getPassword())) {
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        // 校验邮箱是否被使用
        if (checkMailUsed(param.getMail())) {
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }

        // 校验手机号是否被使用
        if (checkPhoneNumberUsed(param.getPhoneNumber())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);

        }
    }

    /**
     * 校验手机号是否被使用
     *
     * @param phoneNumber
     * @return
     */
    private boolean checkPhoneNumberUsed(String phoneNumber) {
        int count = userMapper.countByPhone(new Encrypt(phoneNumber));
        return count > 0;
    }

    /**
     * 校验邮箱是否被使用
     *
     * @param mail
     * @return
     */
    private boolean checkMailUsed(@NotBlank(message = "邮箱不能为空！") String mail) {

        int couunt = userMapper.countByMail(mail);
        return couunt > 0;


    }
}
